#include "qaudioreader.h"
#include "sndfile.h"
#include <string>
#include <QString>

using namespace std;

namespace AudioUtils {

class QAudioReaderPrivate
{
public:
    QAudioReaderPrivate()
        : sf(nullptr)
    {
        memset(&sfinfo, 0, sizeof(SF_INFO));
    }

    ~QAudioReaderPrivate()
    {
        if (sf)
        {
            sf_close(sf);
            sf = nullptr;
        }
    }

public:
    SNDFILE* sf;
    SF_INFO sfinfo;
};

QAudioReader::QAudioReader()
    : p(new QAudioReaderPrivate)
{
}

QAudioReader::~QAudioReader()
{
    delete p;
}

bool QAudioReader::open(const QString &path)
{
    close();
    auto filepath = path.toStdString();
    p->sf = sf_open(filepath.c_str(), SFM_READ, &p->sfinfo);

    if (!p->sf)
    {
        return false;
    }

	if (!sf_format_check(&p->sfinfo))
	{
		close();
		return false;
	}

    return true;
}

void QAudioReader::close()
{
    if (p->sf)
    {
        sf_close(p->sf);
        p->sf = nullptr;
        memset(&p->sfinfo,0,sizeof(SF_INFO));
    }
}

quint64 QAudioReader::seek(quint64 frames, int whence)
{
    return sf_seek(p->sf, frames, whence);
}

quint64 QAudioReader::read(short *ptr, quint64 items)
{
    return sf_read_short(p->sf, ptr, items);
}

quint64 QAudioReader::read(int *ptr, quint64 items)
{
     return sf_read_int(p->sf, ptr, items);
}

quint64 QAudioReader::read(float *ptr, quint64 items)
{
    return sf_read_float(p->sf, ptr, items);
}

quint64 QAudioReader::read(double *ptr, quint64 items)
{
    return sf_read_double(p->sf, ptr, items);
}

quint64 QAudioReader::readf(short *ptr, quint64 frames)
{
    return sf_readf_short(p->sf, ptr, frames);
}

quint64 QAudioReader::readf(int *ptr, quint64 frames)
{
     return sf_readf_int(p->sf, ptr, frames);
}

quint64 QAudioReader::readf(float *ptr, quint64 frames)
{
     return sf_readf_float(p->sf, ptr, frames);
}

quint64 QAudioReader::readf(double *ptr, quint64 frames)
{
    return sf_readf_double(p->sf, ptr, frames);
}

quint64 QAudioReader::readTrack(short *ptr, quint64 frames, quint8 channel)
{
	if (p->sfinfo.channels == 1)
	{
		return read(ptr, frames);
	}

	short* buffer = new short[frames * 2];
	quint64 count = readf(buffer, frames);

	for (int i = 0; i < count; i++)
	{
		ptr[i] = buffer[i * 2 + channel];
	}

	delete[] buffer;
	return count;
}

quint64 QAudioReader::readTrack(int *ptr, quint64 frames, quint8 channel)
{
	if (p->sfinfo.channels == 1)
	{
		return read(ptr, frames);
	}

	int* buffer = new int[frames * 2];
	quint64 count = readf(buffer, frames);

	for (int i = 0; i < count; i++)
	{
		ptr[i] = buffer[i * 2 + channel];
	}

	delete[] buffer;
	return count;
}

quint64 QAudioReader::readTrack(float *ptr, quint64 frames, quint8 channel)
{
	if (p->sfinfo.channels == 1)
	{
		return read(ptr, frames);
	}

	float* buffer = new float[frames * 2];
	quint64 count = readf(buffer, frames);

	for (int i = 0; i < count; i++)
	{
		ptr[i] = buffer[i * 2 + channel];
	}

	delete[] buffer;
	return count;
}

quint64 QAudioReader::readTrack(double *ptr, quint64 frames, quint8 channel)
{
	if (p->sfinfo.channels == 1)
	{
		return read(ptr, frames);
	}

	double* buffer = new double[frames * 2];
	quint64 count = readf(buffer, frames);

	for (int i = 0; i < count; i++)
	{
		ptr[i] = buffer[i * 2 + channel];
	}

	delete[] buffer;
	return count;
}

}
